/*
 * rb112.c
 *
 *  Created on: 13 May 2015
 *      Author: yiqi.pan
 */

#include "common.h"
#include <string.h>
#include "config.h"
#include "bluetooth.h"
#include "rb112.h"
#include "timer_ms.h"
#include "uart.h"
#include "protocol.h"

typedef struct
{
	const char* cmd_str;
	const char* reply_pattern;
}  RB_COMMAND_t;

RB_COMMAND_t rb_command[NR_OF_COMMAND] =
{
	{ "", ""},
	{ "AT+GVER?\r",	"\r\n*\r\n\r\nOK\r\n" },		//CMD_GET_VERSION,
	{ "AT+NAME?\r", "\r\n+NAME:*\r\n\r\nOK\r\n"},			//CMD_GET_NAME,
	{	"AT+PIN?\r", "\r\n+PIN:*\r\n\r\nOK\r\n"},			//CMD_GET_PIN,
	{	"AT+CLASS?\r", "\r\n+CLASS:*\r\n\r\nOK\r\n"},		//CMD_GET_COD,
	{	"AT+LBDADDR?\r", "\r\n+LBDADDR:*\r\n\r\nOK\r\n" }, 	//CMD_GET_BTADDR,
	{	"AT+BAUD?\r", "\r\n+BAUD:*\r\n\r\nOK\r\n", },			//CMD_GET_BAUD
	{	"AT+IOCAP?\r", "\r\n+IOCAP:?\r\n\r\nOK\r\n" },		//CMD_GET_IOCAP
	{	"AT+DISCOVERABLE?\r", "\r\n+DISCOVERABLE:?\r\n\r\nOK\r\n" },//CMD_GET_SPP_DISCOVERABLE
	{	"AT\r", ""},						//CMD_TEST
	{	"AT+NAME=", ""},				//CMD_SET_NAME,
	{	"AT+PIN=", ""},				//CMD_SET_PIN,
	{	"AT+CLASS=", ""},			//CMD_SET_COD
	{	"AT+DISCOVERABLE=", ""}	//CMD_SET_SPP_DISCOVERABLE
};
/*
const char* rb_command_pattern[] =
{
	"",
	"\r\n*\r\n\r\nOK\r\n",						//CMD_GET_VERSION,
	"\r\n+NAME:*\r\n\r\nOK\r\n",			//CMD_GET_NAME,
	"\r\n+PIN:*\r\n\r\nOK\r\n",				//CMD_GET_PIN,
	"\r\n+CLASS:*\r\n\r\nOK\r\n",			//CMD_GET_COD,
	"\r\n+LBDADDR:*\r\n\r\nOK\r\n", 	//CMD_GET_BTADDR,
	"\r\n+BAUD:*\r\n\r\nOK\r\n",			//CMD_GET_BAUD
	"\r\n+IOCAP:?\r\n\r\nOK\r\n",			//CMD_GET_IOCAP
	"\r\n+DISCOVERABLE:?\r\n\r\nOK\r\n", //CMD_GET_SPP_DISCOVERABLE
	"",			//CMD_TEST
	"",	//CMD_SET_NAME,
	"",	//CMD_SET_PIN,
	"",	//CMD_SET_COD

};
*/

const char RB_CMD_END[]= "\r";
#define RB_CMD_END_LENGTH 1


/* RB112 status messages */
const char RB_ST_READY[] = "\r\nIM_READY\r\n";
const char RB_ST_SPP[] = "\r\nIM_SPP\r\n";
const char RB_ST_GATT[] = "\r\nIM_GATT\r\n";
const char RB_ST_CONN_FAIL[] = "\r\nIM_CONN_FAIL\r\n";
const char RB_ST_OK[] = "\r\nOK\r\n";
const char RB_ST_ERROR[] = "\r\nERROR\r\n";


volatile bool connected = false;
volatile uint8_t connect_mode = BT_MODE_NONE;
volatile uint8_t command_result = RB_R_OK;

#define wait_current_cmd_end() do{ while(current_cmd!=CMD_NONE){} } while (0)



typedef enum
{
	CMD_S_NONE,
	CMD_S_RUN,
	CMD_S_DONE
} COMMAND_STATE_t;

typedef struct
{
	char* reply_pattern;
	uint8_t reply_pattern_len;
	COMMAND_STATE_t cmd_state;
	bool result_ok;
	char *result;
	uint8_t result_max_len;
	uint8_t result_len;

} COMMAND_t;

static COMMAND_t cur_cmd = {0};
char data_buffer[32];

int8_t rb_str_parser(uint8_t *data, 
		uint8_t datalen, 
		uint8_t *pattern, 
		uint8_t patternlen, 
		uint8_t *result_start, 
		uint8_t *result_len);

void rb_bt_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;  

    /* Configure GPIO pin ----------------------------*/
    GPIO_InitStructure.GPIO_Pin =  BT_RESET_PIN|BT_DISCONNECT_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(RB112_GPIO_PORT, &GPIO_InitStructure);
    
    /* Set Reset Pin to high */
    GPIO_SetBits(RB112_GPIO_PORT, BT_RESET_PIN);
    
    /* Set Disconnect Pin to low */
    GPIO_ResetBits(RB112_GPIO_PORT, BT_DISCONNECT_PIN);
    
}


int8_t rb_receive_handler(uint8_t* data, uint8_t datalen)
{

	if(connected)
	{
		/* receive "\r\nIM_READY\r\n" */
		if((datalen >= sizeof(RB_ST_READY)-1) && strncmp(RB_ST_READY, (char*)data, datalen)==0)
		{
			connected = false;
			connect_mode = BT_MODE_NONE;
			return 1;
		}
		else
		{
			/* handle by protocol parser */
			return receive_packet(data, datalen);
		}
	}
	else
	{
		/* do we receive "\r\nIM_SPP\r\n" or "\r\nIM_GATT\r\n"  ? */
		if( (datalen >= sizeof(RB_ST_SPP)-1) && strncmp(RB_ST_SPP, (char*)data, datalen)==0)
		{
			connected = true;
			connect_mode = BT_MODE_SPP;
			return 1;
		}
		else if((datalen >= sizeof(RB_ST_GATT)-1) && strncmp(RB_ST_GATT, (char*)data, datalen)==0)
		{
			connected = true;
			connect_mode = BT_MODE_GATT;
			return 1;
		}
		else
		{
			return 0;
			/* if result == 0,  don't do anything, wait for more data to come */
		}
	}

}

/* parse a data string against a pattern
 * return:
 * 	 -1: unmatch
 * 	 0: data is shorter than the pattern
 * 	 1: match
 */

int8_t rb_str_parser(uint8_t *data, 
		uint8_t datalen, 
		uint8_t *pattern, 
		uint8_t patternlen, 
		uint8_t *result_start, 
		uint8_t *result_len)
{
	uint8_t i,j;
	uint8_t rs_start=0,rs_end=0;
	uint8_t expected_len = patternlen;


	for(i=0,j=0; i<datalen && j< patternlen; i++)
	{
		if(pattern[j]=='?')
		{
			j++;
			rs_start = i;
			rs_end = i+1;
			continue;
		}
		else if(pattern[j]=='*')
		{
			j++;
			rs_start = i;
			while(i<datalen-1)
			{
				if(data[i+1]=='\r')
				{
					if(datalen==17)
						data_buffer[0]=1;
					break;
				}
				i++;
				expected_len++;
			}
			rs_end = i+1;
			continue;
		}
		if(data[i] != pattern[j])
		{

			return -1;
		}
		j++;
	}
	if(datalen < expected_len)
		return 0;
	else
	{
		if(result_start)
			*result_start = rs_start;
		if(result_len)
			*result_len = rs_end - rs_start;
		return 1;
	}
}



/* get bluetooth device ID */
uint8_t rb_send_get_cmd(uint8_t cmdid, uint8_t* buf, uint8_t buflen)
{
	uint8_t result_start;
	uint8_t result_len;
	
	assert_param(is_get_command(cmdid));
	bt_uart_send((uint8_t*)(rb_command[cmdid].cmd_str), strlen(rb_command[cmdid].cmd_str));
	timer_ms_start_singleshot(BT_TIMER, RB_GET_TIMEOUT);
	
	while(!timer_ms_test_and_clear_expired(BT_TIMER));

	
	uart_disable_rx(BT_UART);
	if(rb_str_parser(RxBuffer, rxpos, (uint8_t*)rb_command[cmdid].reply_pattern, strlen(rb_command[cmdid].reply_pattern), &result_start, &result_len)>0)
	{
			if(result_len>buflen)
				result_len = buflen;
			memcpy(buf, RxBuffer+result_start, result_len);
			*(buf+result_len) = 0;
	}
	else
	{
		/* timeout */
		result_len = 0;
	}

	bt_uart_reset_rx_buffer();
	uart_enable_rx(BT_UART);
	return result_len;
}


uint8_t rb_send_set_cmd(uint8_t cmdid, uint8_t *data, uint8_t datalen)
{
	uint8_t cmdlen;
	uint8_t buf[32];
	uint8_t result;

	assert_param(is_set_command(cmdid));
	cmdlen = strlen(rb_command[cmdid].cmd_str);
	memcpy(buf, rb_command[cmdid].cmd_str, cmdlen);
	memcpy(buf + cmdlen, data, datalen);
	memcpy(buf + cmdlen + datalen, RB_CMD_END, RB_CMD_END_LENGTH);
	bt_uart_send(buf, cmdlen + datalen + RB_CMD_END_LENGTH);
	timer_ms_start_singleshot(BT_TIMER, RB_SET_TIMEOUT);

	while(!timer_ms_test_and_clear_expired(BT_TIMER));
	
	uart_disable_rx(BT_UART);
	if(rb_str_parser(RxBuffer, rxpos, (uint8_t*)RB_ST_OK, sizeof(RB_ST_OK)-1, NULL, NULL)>0)
	{
			result = 1;
	}
	else
	{		
		result = 0;
	}
	bt_uart_reset_rx_buffer();
	uart_enable_rx(BT_UART);
	return result;

}

/* check if a uart connect is established over bluetooth */
void rb_bt_is_connected(void)
{

}

/* disconnect the current connection */
void rb_bt_disconnect(void)
{

}

/* hard reset bluetooth module */
void rb_bt_hw_reset(void)
{

}

/* configure the RB112 for the first time */
void rb_config(void)
{

}

/* send data via bluetooth uart */
void rb_bt_send(uint8_t* data, uint8_t datalen)
{

}


#ifdef TEST
#include "led.h"
void TEST_rb_str_parser(void)
{
	uint8_t *data, *pt;
	uint8_t datalen, ptlen;
	uint8_t result_start,result_len;
	char buf[20];

	led_off();
	
	data = "\r\n+BAUD:115200\r\n\r\nOK\r\n";
	pt = "\r\n+BAUD:*\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= 1)
		led_on();
		
	data = "\r+IOCAP:1\r\n\r\nOK\r\n";
	pt = "\r\n+IOCAP:1\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= -1)
		led_on();

	data = "\r\n+IOCAP:1\r\n\r\nK\r\n";
	pt = "\r\n+IOCAP:1\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= -1)
		led_on();
		
	data = "\r\n+IOCAP:12\r\n\r\nOK\r\n";
	pt = "\r\n+IOCAP:?\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= -1)
		led_on();	

	data = "\r\n+IOCAP:1\r\n\nOK\r\n";
	pt = "\r\n+IOCAP:?\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= -1)
		led_on();

	data = "\r\n+ItCAP:1\r\n\nOK\r\n";
	pt = "\r\n+IOCAP:?\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= -1)
		led_on();

	data = "\r\n+IOCAP:1\r\n\nOK\r1\n";
	pt = "\r\n+IOCAP:?\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= -1)
		led_on();

	data = "\r\n+IOCAP:1\r\n\r\nOK\r\n";
	pt =   "\r\n+IOCAP:?\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= 1)
		led_on();

	data = "\r\nBSE_DATA_2.1.1\r\n\r\nOK\r\n";
	pt = "\r\n*\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= 1)
		led_on();
	
	data = "\r\n+NAME:hccm\r\n\r\nOK\r\n";
	pt = "\r\n+NAME:*\r\n\r\nOK\r\n";
	datalen = strlen(data);
	ptlen = strlen(pt);
	if(rb_str_parser(data,datalen, pt, ptlen, &result_start,&result_len)!= 1)
		led_on();
	memcpy(buf, data+result_start, result_len);
	led_off();

}
#endif
